from datetime import date, datetime

from django.db.models import Count

from gis.admin.decorators import list_func
from gis.common import track_logging
from gis.common.django_ext.models import paginate
from gis.common.exceptions import BizException
from gis.common.timer import api as timer_api
from . import order_service
from .const import *
from .errors import *
from .models import *
from itpay.utils import maestro_tracker

_LOGGER = track_logging.getLogger(__name__)


def convert_star_to_rank_value(comment_star):
    if comment_star.value < OrderCommentStar.THREE.value:
        return OrderCommentRank.BAD.value
    elif comment_star == OrderCommentStar.THREE:
        return OrderCommentRank.NORMAL.value
    else:
        return OrderCommentRank.GOOD.value


def had_order_comment(order_id):
    return Comment.objects.filter(order_id=order_id).exists()


def get_comment_by_id(comment_id):
    assert comment_id
    comment = Comment.objects.filter(id=comment_id).first()
    return comment.to_dict()


def add_pay_order_comment(order_id, comment_star, comment_content=None, auto_comment=False):
    assert isinstance(comment_star, OrderCommentStar)
    pay_order = order_service.get_order_by_id(order_id)

    if OrderStatus(pay_order['status']) not in [OrderStatus.SUCCESS, OrderStatus.CHASE_FROZEN]:
        raise BizException(ERROR_ORDER_STATUS_CONFLICT, pay_order['status'])

    if not pay_order['can_comment']:
        raise BizException(ERROR_ORDER_CAN_NOT_COMMENT)

    if had_order_comment(order_id):
        raise BizException(ERROR_ORDER_COMMENT_EXISTS)
    comment = Comment()
    comment.order_id = order_id
    comment.agency_id = pay_order['agency_id']
    comment.mch_id = pay_order['mch_id']
    comment.user_id = pay_order['user_id']

    comment.amount = pay_order['amount']
    comment.real_amount = pay_order['real_amount']
    comment.recharge_amount = pay_order['recharge_amount']
    comment.success_at = pay_order['success_at']

    comment.pay_type = pay_order['pay_type']
    comment.receipt_type = pay_order['receipt_type']

    comment.comment_star = comment_star.value
    comment.comment_rank = convert_star_to_rank_value(comment_star)
    comment.comment_content = comment_content
    comment.auto_comment = auto_comment
    comment.save()
    timer_api.cancel_task(TASK_ORDER_AUTO_COMMENT, order_id)

    try:
        maestro_tracker.track_maestro_user_recharge_comment(comment.id,
                                                            int(datetime.strftime(comment.success_at, '%s')),
                                                            comment.agency_id,
                                                            comment.mch_id, comment.user_id,
                                                            comment.comment_star, comment.comment_rank, auto_comment)
    except Exception:
        _LOGGER.info("track_maestro_user_recharge_comment error {}".format(comment.id), exc_info=True)

    return comment.to_dict()


@list_func
def list_pay_order_comment(page_no, page_size, order_id=None, user_id=None, mch_id=None, agency_id=None,
                           agency_name=None, parent_name=None, comment_rank=None, comment_star=None,
                           created_at_begin=None, created_at_end=None, updated_at_begin=None, updated_at_end=None,
                           pay_type=None, receipt_type=None, auto_comment=None, order_by='-updated_at', parent_id=None):
    query = Comment.objects.filter()
    if order_id:
        query = query.filter(order_id=order_id)
    if user_id:
        query = query.filter(user_id=user_id)
    if mch_id:
        query = query.filter(mch_id=mch_id)
    if agency_id:
        query = query.filter(agency_id=agency_id)
    if agency_name:
        query = query.filter(agency__user_name__contains=agency_name)
    if parent_name:
        query = query.filter(agency__parent__user_name__contains=parent_name)
    if parent_id:
        query = query.filter(agency__parent_id=parent_id)
    if comment_rank:
        query = query.filter(comment_rank=comment_rank.value)
    if comment_star:
        query = query.filter(comment_star=comment_star.value)
    if created_at_begin:
        query = query.filter(created_at__gte=created_at_begin)
    if created_at_end:
        query = query.filter(created_at__lte=created_at_end)
    if updated_at_begin:
        query = query.filter(updated_at__gte=updated_at_begin)
    if updated_at_end:
        query = query.filter(updated_at__lte=updated_at_end)
    if pay_type:
        query = query.filter(pay_type=pay_type.value)
    if receipt_type:
        query = query.filter(receipt_type=receipt_type.value)
    if auto_comment is not None:
        query = query.filter(auto_comment=auto_comment)
    if order_by:
        query = query.order_by(order_by)
    return query.count(), [e.to_dict() for e in paginate(query, page_no, page_size)]


def get_month_good_comment_count(agency_id):
    today = date.today()
    first_day = datetime(year=today.year, month=today.month, day=1)
    result = Comment.objects.filter(agency_id=agency_id, comment_rank=OrderCommentRank.GOOD.value,
                                    success_at__gte=first_day).aggregate(
        good_comment_count=Count("*"))
    return result['good_comment_count']


class AutoCommentHandler(timer_api.TaskHandler):
    def handle(self, task):
        order_id = int(task.biz_num)
        try:
            add_pay_order_comment(order_id, OrderCommentStar.FIVE, auto_comment=True)
        except BizException as e:
            _LOGGER.info('order auto comment biz exception, order_id: {}, cause: {}'.format(order_id, e))
        except Exception as e:
            _LOGGER.exception("order auto comment unknown exception order_id: {}, cause: {}".format(order_id, e))

    def get_biz_code(self):
        return TASK_ORDER_AUTO_COMMENT
